home *** CD-ROM | disk | FTP | other *** search
/ NeXTSTEP 3.3 (Developer)…68k, x86, SPARC, PA-RISC] / NeXTSTEP 3.3 Dev Intel.iso / NextDeveloper / Source / GNU / emacs / oldXMenu / Activate.c next >
C/C++ Source or Header  |  1991-11-16  |  15KB  |  532 lines

  1. /* $Header: Activate.c,v 1.16 88/02/02 19:08:46 jim Exp $ */
  2. /* Copyright    Massachusetts Institute of Technology    1985    */
  3.  
  4. #include "copyright.h"
  5.  
  6. /*
  7.  * XMenu:    MIT Project Athena, X Window system menu package
  8.  *
  9.  *    XMenuActivate -    Maps a given menu to the display and activates
  10.  *            the menu for user selection.  The user is allowed to
  11.  *            specify which pane and selection will be current,
  12.  *            the X and Y location of the menu (relative to the
  13.  *            parent window) and the mouse button event mask that
  14.  *            will be used to identify a selection request.
  15.  *
  16.  *            A menu selection is shown to be current by placing
  17.  *            a highlight box around the selection as the mouse
  18.  *            cursor enters its active region.  Inactive selections
  19.  *            will not be highlited.    As the mouse cursor moved
  20.  *            from one menu pane to another menu pane the pane being
  21.  *            entered is raised and made current and the pane being
  22.  *            left is lowered.
  23.  *
  24.  *            Anytime XMenuActivate returns, the p_num and
  25.  *            s_num are left at their last known values (i.e.,
  26.  *            the last known current pane and selection indices).
  27.  *            The following are the defined return states:
  28.  *
  29.  *            1)    If at any time an error occurs the data
  30.  *                pointer is left untouched and XM_FAILURE
  31.  *                is returned.  
  32.  *
  33.  *            2)    When a selection request is recieved (i.e.,
  34.  *                when the specified mouse event occurs) the
  35.  *                data pointer will be set to the data
  36.  *                associated with the particular selection
  37.  *                current at the time of the selection request
  38.  *                and XM_SUCCESS is returned.
  39.  *
  40.  *            3)    If no selection was current at the time a
  41.  *                selection request is made the data pointer
  42.  *                will be left untouched and XM_NO_SELECT will
  43.  *                be returned.
  44.  *
  45.  *            4)    If the selection that was current at the time 
  46.  *                a selection request is made is not an active
  47.  *                selection the data pointer will be left
  48.  *                untouched and XM_IA_SELECT will be returned.
  49.  *
  50.  *            Since X processes events in an asynchronous manner
  51.  *            it is likely that XMenuActivate will encounter
  52.  *            a "foreign event" while it is executing.  Foreign
  53.  *            events are handled in one of three ways:
  54.  *
  55.  *            1)    The event is discarded.  This is the default
  56.  *                mode and requires no action on the part of the
  57.  *                application.
  58.  *
  59.  *            2)    The application has identified an asynchronous
  60.  *                event handler that will be called and the
  61.  *                foreign event handed off to it.  Note:
  62.  *                AEQ mode disables this mode temporarily.
  63.  *
  64.  *            3)    The application has enabled asynchronous event
  65.  *                queueing mode.  In this mode all foreign events
  66.  *                will be    queued up untill XMenuActivate
  67.  *                terminates; at which time they will be
  68.  *                returned to the    X event queue.  As long as
  69.  *                AEQ mode is enabled any asynchronous event
  70.  *                handler as temporarily disabled.
  71.  *
  72.  *            Any events encountered while taking down the menu
  73.  *            (i.e., exposure events from occluded windows) will
  74.  *            automatically be returned to the X event queue after
  75.  *            XMenuActivate has cleaned the queue of any of its own
  76.  *            events that are no longer needed.
  77.  *
  78.  *    Author:        Tony Della Fera, DEC
  79.  *            March 12, 1986
  80.  *
  81.  */
  82.  
  83. #include "XMenuInt.h"
  84.  
  85. int
  86. XMenuActivate(display, menu, p_num, s_num, x_pos, y_pos, event_mask, data)
  87.     register Display *display;        /* Display to put menu on. */
  88.     register XMenu *menu;        /* Menu to activate. */
  89.     int *p_num;                /* Pane number selected. */
  90.     int *s_num;                /* Selection number selected. */
  91.     int x_pos;                /* X coordinate of menu position. */
  92.     int y_pos;                /* Y coordinate of menu position. */
  93.     unsigned int event_mask;        /* Mouse button event mask. */
  94.     char **data;            /* Pointer to return data value. */
  95. {
  96.     int status;                /* X routine call status. */
  97.     int orig_x;                /* Upper left menu origin X coord. */
  98.     int orig_y;                /* Upper left menu origin Y coord. */
  99.     int ret_val;            /* Return value. */
  100.  
  101.     register XMPane *p_ptr;        /* Current XMPane. */
  102.     register XMPane *event_xmp;        /* Event XMPane pointer. */
  103.     register XMPane *cur_p;        /* Current pane. */
  104.     register XMSelect *cur_s;        /* Current selection. */
  105.     XMWindow *event_xmw;        /* Event XMWindow pointer. */
  106.     XEvent event;            /* X input event. */
  107.     XEvent peek_event;            /* X input peek ahead event. */
  108.  
  109.     Bool selection = False;        /* Selection has been made. */
  110.     Bool forward = True;        /* Moving forward in the pane list. */
  111.  
  112.     Window root, child;
  113.     int root_x, root_y, win_x, win_y;
  114.     unsigned int mask;
  115.  
  116.     /*
  117.      * Define and allocate a foreign event queue to hold events
  118.      * that don't belong to XMenu.  These events are later restored
  119.      * to the X event queue.
  120.      */
  121.     typedef struct _xmeventque {
  122.     XEvent event;
  123.     struct _xmeventque *next;
  124.     } XMEventQue;
  125.  
  126.     XMEventQue *feq = NULL;            /* Foreign event queue. */
  127.     XMEventQue *feq_tmp;        /* Foreign event queue temporary. */
  128.     
  129.     /*
  130.      * If there are no panes in the menu then return failure
  131.      * because the menu is not initialized.
  132.      */
  133.     if (menu->p_count == 0) {
  134.     _XMErrorCode = XME_NOT_INIT;
  135.     return(XM_FAILURE);
  136.     }
  137.  
  138.     /*
  139.      * Find the desired current pane.
  140.      */
  141.     cur_p = _XMGetPanePtr(menu, *p_num);
  142.     if (cur_p == NULL) {
  143.     return(XM_FAILURE);
  144.     }
  145.     cur_p->activated = cur_p->active;
  146.  
  147.     /*
  148.      * Find the desired current selection.
  149.      * If the current selection index is out of range a null current selection
  150.      * will be assumed and the cursor will be placed in the current pane
  151.      * header.
  152.      */
  153.     cur_s = _XMGetSelectionPtr(cur_p, *s_num);
  154.  
  155.     /*
  156.      * Compute origin of menu so that cursor is in
  157.      * Correct pane and selection.
  158.      */
  159.     _XMTransToOrigin(display, 
  160.              menu, 
  161.              cur_p, cur_s, 
  162.              x_pos, y_pos, 
  163.              &orig_x, &orig_y);
  164.     menu->x_pos = orig_x;    /* Store X and Y coords of menu. */
  165.     menu->y_pos = orig_y;
  166.     
  167.     if (XMenuRecompute(display, menu) == XM_FAILURE) {
  168.     return(XM_FAILURE);
  169.     }
  170.  
  171.     /*
  172.      * Flush the window creation queue.
  173.      * This batches all window creates since lazy evaluation
  174.      * is more efficient than individual evaluation.
  175.      * This routine also does an XFlush().
  176.      */
  177.     if (_XMWinQueFlush(display, menu, cur_p, cur_s) == _FAILURE) {
  178.     return(XM_FAILURE);
  179.     }
  180.  
  181.     /*
  182.      * Make sure windows are in correct order (in case we were passed
  183.      * an already created menu in incorrect order.)
  184.      */
  185.     for(p_ptr = menu->p_list->next; p_ptr != cur_p; p_ptr = p_ptr->next)
  186.     XRaiseWindow(display, p_ptr->window);
  187.     for(p_ptr = menu->p_list->prev; p_ptr != cur_p->prev; p_ptr = p_ptr->prev)
  188.     XRaiseWindow(display, p_ptr->window);
  189.  
  190.     /*
  191.      * Make sure all selection windows are mapped.
  192.      */
  193.     for (
  194.     p_ptr = menu->p_list->next;
  195.     p_ptr != menu->p_list;
  196.     p_ptr = p_ptr->next
  197.     ){
  198.     XMapSubwindows(display, p_ptr->window);
  199.     }
  200.  
  201.     /*
  202.      * Synchronize the X buffers and the event queue.
  203.      * From here on, all events in the queue that don't belong to
  204.      * XMenu are sent back to the application via an application
  205.      * provided event handler or discarded if the application has
  206.      * not provided an event handler.
  207.      */
  208.     XSync(display, 0);
  209.     
  210.     /*
  211.      * Grab the mouse for menu input.
  212.      */
  213.     
  214.     status = XGrabPointer(
  215.               display,
  216.               menu->parent,
  217.               True,
  218.               event_mask,
  219.               GrabModeAsync,
  220.               GrabModeAsync,
  221.               None,
  222.               menu->mouse_cursor,
  223.               CurrentTime
  224.               );
  225.     if (status == _X_FAILURE) {
  226.     _XMErrorCode = XME_GRAB_MOUSE;
  227.     return(XM_FAILURE);
  228.     }
  229.  
  230.     /*
  231.      * Map the menu panes.
  232.      */
  233.     XMapWindow(display, cur_p->window);
  234.     for (p_ptr = menu->p_list->next;
  235.      p_ptr != cur_p; 
  236.      p_ptr = p_ptr->next)
  237.       XMapWindow(display, p_ptr->window);
  238.     for (p_ptr = cur_p->next;
  239.      p_ptr != menu->p_list;
  240.      p_ptr = p_ptr->next)
  241.       XMapWindow(display, p_ptr->window);
  242.  
  243.     XRaiseWindow(display, cur_p->window);    /* Make sure current */
  244.                         /* pane is on top. */
  245.     
  246.     cur_s = NULL;            /* Clear current selection. */
  247.  
  248.     /*
  249.      * Begin event processing loop.
  250.      */
  251.     while (1) {
  252.     XNextEvent(display, &event);    /* Get next event. */
  253.     switch (event.type) {        /* Dispatch on the event type. */
  254.     case Expose:
  255.         event_xmp = (XMPane *)XLookUpAssoc(display,
  256.                            menu->assoc_tab, 
  257.                            event.xexpose.window);
  258.         if (event_xmp == NULL) {
  259.         /*
  260.          * If AEQ mode is enabled then queue the event.
  261.          */
  262.         if (menu->aeq) {
  263.             feq_tmp = (XMEventQue *)malloc(sizeof(XMEventQue));
  264.             if (feq_tmp == NULL) {
  265.             _XMErrorCode = XME_CALLOC;
  266.             return(XM_FAILURE);
  267.             }
  268.             feq_tmp->event = event;
  269.             feq_tmp->next = feq;
  270.             feq = feq_tmp;
  271.         }
  272.         else if (_XMEventHandler) (*_XMEventHandler)(&event);
  273.         break;
  274.         }
  275.         if (event_xmp->activated) {
  276.         XSetWindowBackground(display,
  277.                      event_xmp->window, 
  278.                      menu->bkgnd_color);
  279.         }
  280.         else {
  281.         XSetWindowBackgroundPixmap(display,
  282.                        event_xmp->window,
  283.                        menu->inact_pixmap);
  284.         }
  285.         _XMRefreshPane(display, menu, event_xmp);
  286.         break;
  287.     case EnterNotify:
  288.         /* 
  289.          * First wait a small period of time, and see
  290.          * if another EnterNotify event follows hard on the
  291.          * heels of this one. i.e., the user is simply
  292.          * "passing through". If so, ignore this one.
  293.          */
  294.     
  295.         event_xmw = (XMWindow *)XLookUpAssoc(display,
  296.                          menu->assoc_tab,
  297.                          event.xcrossing.window);
  298.         if (event_xmw == NULL) break;
  299.         if (event_xmw->type == SELECTION) {
  300.         /*
  301.          * We have entered a selection.
  302.          */
  303.         /* if (XPending(display) == 0) usleep(150000); */
  304.         if (XPending(display) != 0) {
  305.             XPeekEvent(display, &peek_event);
  306.             if(peek_event.type == LeaveNotify) {
  307.             break;
  308.             }
  309.         }              
  310.         cur_s = (XMSelect *)event_xmw;
  311.         /*
  312.          * If the pane we are in is active and the
  313.          * selection entered is active then activate
  314.          * the selection.
  315.          */
  316.         if (cur_p->active && cur_s->active) {
  317.             cur_s->activated = 1;
  318.             _XMRefreshSelection(display, menu, cur_s);
  319.         }
  320.         }
  321.         else {
  322.         /*
  323.          * We have entered a pane.
  324.          */
  325.         /* if (XPending(display) == 0) usleep(150000); */
  326.         if (XPending(display) != 0) {
  327.             XPeekEvent(display, &peek_event);
  328.             if (peek_event.type == EnterNotify) break;
  329.         }
  330.         XQueryPointer(display,
  331.                   menu->parent,
  332.                   &root, &child,
  333.                   &root_x, &root_y,
  334.                   &win_x, &win_y,
  335.                   &mask);
  336.         event_xmp = (XMPane *)XLookUpAssoc(display,
  337.                            menu->assoc_tab,
  338.                            child);
  339.         if (event_xmp == NULL) break;
  340.         if (event_xmp == cur_p) break;
  341.         if (event_xmp->serial > cur_p->serial) forward = True;
  342.         else forward = False;
  343.         p_ptr = cur_p;
  344.         while (p_ptr != event_xmp) {
  345.             if (forward) p_ptr = p_ptr->next;
  346.             else p_ptr = p_ptr->prev;
  347.             XRaiseWindow(display, p_ptr->window);
  348.         }
  349.         if (cur_p->activated) {
  350.             cur_p->activated = False;
  351.             XSetWindowBackgroundPixmap(display,
  352.                            cur_p->window,
  353.                            menu->inact_pixmap);
  354.             _XMRefreshPane(display, menu, cur_p);
  355.         }
  356.         if (event_xmp->active) event_xmp->activated = True;
  357.         cur_p = event_xmp;
  358.         }
  359.         break;
  360.     case LeaveNotify:
  361.         event_xmw = (XMWindow *)XLookUpAssoc(
  362.                          display,
  363.                          menu->assoc_tab,
  364.                          event.xcrossing.window
  365.                          );
  366.         if (event_xmw == NULL) break;
  367.         if(cur_s == NULL) break;
  368.         
  369.         /*
  370.          * If the current selection was activated then
  371.          * deactivate it.
  372.          */
  373.         if (cur_s->activated) {
  374.         cur_s->activated = False;
  375.         _XMRefreshSelection(display, menu, cur_s);
  376.         }
  377.         cur_s = NULL;
  378.         break;
  379.     
  380.     case ButtonPress:
  381.     case ButtonRelease:
  382.         *p_num = cur_p->serial;
  383.         /*
  384.          * Check to see if there is a current selecion.
  385.          */
  386.         if (cur_s != NULL) {
  387.             /*
  388.              * Set the selection number to the current selection.
  389.              */
  390.             *s_num = cur_s->serial;
  391.             /*
  392.              * If the current selection was activated then
  393.              * we have a valid selection otherwise we have
  394.              * an inactive selection.
  395.              */
  396.             if (cur_s->activated) {
  397.             *data = cur_s->data;
  398.             ret_val = XM_SUCCESS;
  399.             }
  400.             else {
  401.             ret_val = XM_IA_SELECT;
  402.             }
  403.         }
  404.         else {
  405.             /*
  406.              * No selection was current.
  407.              */
  408.             ret_val = XM_NO_SELECT;
  409.         }
  410.         selection = True;
  411.         break;
  412.         default:
  413.         /*
  414.          * If AEQ mode is enabled then queue the event.
  415.          */
  416.         if (menu->aeq) {
  417.             feq_tmp = (XMEventQue *)malloc(sizeof(XMEventQue));
  418.             if (feq_tmp == NULL) {
  419.             _XMErrorCode = XME_CALLOC;
  420.             return(XM_FAILURE);
  421.             }
  422.             feq_tmp->event = event;
  423.             feq_tmp->next = feq;
  424.             feq = feq_tmp;
  425.         }
  426.         else if (_XMEventHandler) (*_XMEventHandler)(&event);
  427.     }
  428.     /*
  429.      * If a selection has been made, break out of the event loop.
  430.      */
  431.     if (selection == True) break;
  432.     }
  433.  
  434.     /*
  435.      * Unmap the menu.
  436.      */
  437.     for ( p_ptr = menu->p_list->next;
  438.      p_ptr != menu->p_list;
  439.      p_ptr = p_ptr->next) 
  440.       {
  441.       XUnmapWindow(display, p_ptr->window);
  442.       }
  443.  
  444.     /*
  445.      * Ungrab the mouse.
  446.      */
  447.     XUngrabPointer(display, CurrentTime);
  448.  
  449.     /* 
  450.      * Restore bits under where the menu was if we managed
  451.      * to save them and free the pixmap.
  452.      */
  453.  
  454.     /*
  455.      * If there is a current selection deactivate it.
  456.      */
  457.     if (cur_s != NULL) cur_s->activated = 0;
  458.  
  459.     /*
  460.      * Deactivate the current pane.
  461.      */
  462.     cur_p->activated = 0;
  463.     XSetWindowBackgroundPixmap(display, cur_p->window, menu->inact_pixmap);
  464.  
  465.     /*
  466.      * Synchronize the X buffers and the X event queue.
  467.      */
  468.     XSync(display, 0);
  469.     
  470.     /*
  471.      * Dispatch any events remaining on the queue.
  472.      */
  473.     while (QLength(display)) {
  474.     /*
  475.      * Fetch the next event.
  476.      */
  477.     XNextEvent(display, &event);
  478.  
  479.     /*
  480.      * Discard any events left on the queue that belong to XMenu.
  481.      * All others are held and then returned to the event queue.
  482.      */
  483.     switch (event.type) {
  484.         case Expose:
  485.         case EnterNotify:
  486.         case LeaveNotify:
  487.         case ButtonPress:
  488.         case ButtonRelease:
  489.         /*
  490.          * Does this event belong to one of XMenu's windows?
  491.          * If so, discard it and process the next event.
  492.          * If not fall through and treat it as a foreign event.
  493.          */
  494.         event_xmp = (XMPane *)XLookUpAssoc(
  495.                            display,
  496.                            menu->assoc_tab,
  497.                            event.xbutton.window
  498.                            );
  499.         if (event_xmp != NULL) continue;
  500.         default:
  501.         /*
  502.          * This is a foreign event.
  503.          * Queue it for later return to the X event queue.
  504.          */
  505.         feq_tmp = (XMEventQue *)malloc(sizeof(XMEventQue));
  506.         if (feq_tmp == NULL) {
  507.             _XMErrorCode = XME_CALLOC;
  508.             return(XM_FAILURE);
  509.         }
  510.         feq_tmp->event = event;
  511.         feq_tmp->next = feq;
  512.         feq = feq_tmp;
  513.         }
  514.     }
  515.     /*
  516.      * Return any foreign events that were queued to the X event queue.
  517.      */
  518.     while (feq != NULL) {
  519.     feq_tmp = feq;
  520.     XPutBackEvent(display, &feq_tmp->event);
  521.     feq = feq_tmp->next;
  522.     free((char *)feq_tmp);
  523.     }
  524.     
  525.     /*
  526.      * Return successfully.
  527.      */
  528.     _XMErrorCode = XME_NO_ERROR;
  529.     return(ret_val);
  530.  
  531. }
  532.